
#import "WWTCLInterp.h"
#import "WWTCLInterpIBInspector.h"
#import "NIBNameCell.h"
#import "NIBNameMatrix.h"
#import "NIBNameScrollView.h"

#import <strings.h>
#import <ctype.h>


@implementation WWTCLInterpIBInspector

/*
==========================================================================
subext() -- Remove extension from fname only if it is there.

==========================================================================
*/
static char 
*subext(fname, ext)
register char *fname, *ext;
{
  int fl, el;

	for ( fl = strlen(fname), el = strlen(ext);
		--el > -1 && --fl > -1 && fname[fl] == ext[el]; )
		;
	if (el == -1) 
	{  fname[fl] = '\0';
	}
	return(fname);
}


/*
==========================================================================
basename() -- deletes any prefix ending in `/' and the suffix.

==========================================================================
*/
static char 
*basename(str, sfx, dest)
char *str, *sfx, *dest;
{
char temp[1024];
char *p, *p1;
char *subext();

	p = p1 = temp;
	strcpy(p, str);
	while (*p) 
	{  if (*p++ == '/') 
           {  p1 = p;
	   }
	}
	strcpy (dest, subext(p1, sfx));
	return(dest);
}

- init
{
   id      bundle, retId;
   char    path[MAXPATHLEN + 1];
   NXRect  scrollRect, matrixRect;
   NXSize  interCellSpacing = {0.0, 0.0}, cellSize;
   int     i, howManyArchives;
   char    **argv;
   id      newCell;

    
   [super init];

   bundle = [NXBundle bundleForClass: [WWTCLInterp class]];

   if (!bundle) 
   {  NXLogError("No bundle for Class %s.\n", [WWTCLInterp name]);
      return nil;
   }
			
   if (![bundle getPath: path forResource: "WWTCLInterpIBInspector" ofType: "nib"])
   {  NXLogError("No path for %s.\n", "WWTCLInterpIBInspector.nib");
      return nil;
   }
			
   if (![NXApp loadNibFile:path owner:self  withNames:NO fromZone:[self zone]])
   {  NXLogError("problem loading %s.\n");
      return nil;
   }
  /* set the scrollView's attributes */
  [nibNameScrollView setBorderType:NX_BEZEL];
  [nibNameScrollView setVertScrollerRequired:YES];
  [nibNameScrollView setHorizScrollerRequired:YES];
  [nibNameScrollView setAutoresizeSubviews:YES];
		
  /* get the scrollView's dimensions */
    [nibNameScrollView getFrame:&scrollRect];

  /* determine the matrix bounds */
    [ScrollView getContentSize:&(matrixRect.size)
    		forFrameSize:&(scrollRect.size)
		horizScroller:YES
		vertScroller:YES
		borderType:NX_BEZEL];
    
  /* prepare a matrix to go inside our scrollView */
    matrixRect.origin.x = matrixRect.origin.y = 0.0;
    nibNameMatrix = [[NIBNameMatrix alloc] initFrame:&matrixRect 
                                                      mode:NX_LISTMODE
                                                      cellClass:[TextFieldCell class]
                                                      numRows:0
                                                      numCols:1];

  /* we don't want any space between the matrix's cells  */
    [nibNameMatrix setIntercell:&interCellSpacing];
      
  /* resize the matrix's cells and size the matrix to contain them */
    [nibNameMatrix getCellSize:&cellSize];
    cellSize.width = NX_WIDTH(&matrixRect);
    [nibNameMatrix setCellSize:&cellSize];
    [nibNameMatrix sizeToCells];
    [nibNameMatrix setAutosizeCells:YES];
    
  /*
   * when the user clicks in the matrix and then drags the mouse out of
   * scrollView's contentView, we want the matrix to scroll
   */
    [nibNameMatrix setAutoscroll:YES];
    [nibNameMatrix setScrollable:YES];
    
    /* make it so the archive knows about the inspector; this is so when something gets cut we stay in synch. */
    [nibNameMatrix setTheInspector:self];

  /* stick the matrix in our scrollView */
    retId = [nibNameScrollView setMyMatrix:nibNameMatrix];
    retId = [nibNameScrollView setDocView:nibNameMatrix];
    retId = [nibNameScrollView docView];

  /* set things up so that the matrix will resize properly */
    [[nibNameMatrix superview] setAutoresizeSubviews:YES];
    [nibNameMatrix setAutosizing:NX_WIDTHSIZABLE];
    
  /* set the matrix's single- and double-click actions */
    [nibNameMatrix setTarget:self];
    [nibNameMatrix setAction:@selector(singleClick:)];
    [nibNameMatrix setDoubleAction:@selector(doubleClick:)];
    
   howManyArchives = [object nibNameArgc];
   argv = [object nibNameArgv];

   for (i = 0; i < howManyArchives; i++)
   {  [nibNameMatrix addRow];
      [nibNameMatrix sizeToCells];
      newCell = [nibNameMatrix cellAt:i :0];
      [newCell setStringValue:argv[i]];
   }

  /* select a cell, for starters */
   [[nibNameMatrix selectCellAt:0 :0] sendAction];

   [self revert: nil];

   return self;
}


- singleClick:sender
{  //fprintf(stderr, "been single-clicked\n"); return self;
   return self;
}


- doubleClick:sender
{  
  char        filename[MAXPATHLEN+1];
  const char  *path;
  id          aCell, 
              aList = nil;
  int         row, col, i;


  //fprintf(stderr, "been double-clicked\n");
  path = [object pathInIB];
  if (!path)
  {  NXRunAlertPanel("Yo!", 
	             "you better set the pathInIB if you want me to be able to open a nib file when you double-click...", 
                     NULL, NULL, NULL);
     return self;
  }

  aList = [[List alloc] init];
  [nibNameMatrix getSelectedCells:aList];
  if ([aList count])
  {  for (i = 0; i < [aList count]; i++)
     {  aCell = [aList objectAt:i];
        [nibNameMatrix getRow:&row andCol:&col ofCell:aCell];
        sprintf(filename, "%s/%s.nib", path, [aCell stringValue]);
        //NXLogError("asking the Workspace to open nib file %s...\n", filename);
        [[Application workspace] openFile:filename];
     }
  }
  else
  {  aCell = [nibNameMatrix selectedCell];
     [nibNameMatrix getRow:&row andCol:&col ofCell:aCell];
     sprintf(filename, "%s/%s.nib", path, [aCell stringValue]);
     //NXLogError("asking the Workspace to open nib file %s...\n", filename);
     [[Application workspace] openFile:filename];
  }
  [aList free];
  
  return self;
}


- (BOOL)wantsButtons
{
    	return YES;
}


//  Must always call [super revert:].
- revert:sender
{
   int     i, howManyArchives;
   char    **argv;
   id      newCell;


   [nibNameText setStringValue:""];

   // empty out the NibName matrix in preparation for refilling it.
   howManyArchives = [[nibNameMatrix cellList] count];
   for (i = 0; i < howManyArchives; i++)
   {  [nibNameMatrix removeRowAt:0 andFree:YES];
      [nibNameMatrix sizeToCells];
   }
   howManyArchives = [object nibNameArgc];
   argv = [object nibNameArgv];
   for (i = 0; i < howManyArchives; i++)
   {  [nibNameMatrix addRow];
      [nibNameMatrix sizeToCells];
      newCell = [nibNameMatrix cellAt:i :0];
      [newCell setStringValue:argv[i]];
   }
  /* select a cell, for starters */
   [[nibNameMatrix selectCellAt:0 :0] sendAction];

   [pathInIBText setStringValue:[object pathInIB]];

   return [super revert:sender];
}


- notok: sender
{
  return [super ok:sender];
}

- ok: sender
{
   int   i, realCnt;
   char  *cellStr;
   char  **argv;


  //  Must always call [super ok:].

  argv = (char **)calloc(64, sizeof(char *));

  [self addNibName:[nibNameText stringValue]];

   // need to grab text out of nibNameText.  If not empty, alloc a new Cell for the nibMatrix 
   // free the old version
   realCnt = 0;
   for (i = 0; i < [[nibNameMatrix cellList] count]; i++)
   {  if ([[[nibNameMatrix cellList] objectAt:i] stringValue])
      {  realCnt++;
      }
   }
   realCnt = 0;
   for (i = 0; i < [[nibNameMatrix cellList] count]; i++)
   {  cellStr = (char *)[[[nibNameMatrix cellList] objectAt:i] stringValue];
      if (cellStr != NULL)
      {  argv[i] = NXCopyStringBuffer(cellStr);
         realCnt++;
      }
   }
   [object setNibNameArgc:realCnt Argv:argv];
   for (i = 0; i < realCnt; i++)
   {  free(argv[i]);
   }
   free(argv);

   // set the value back to an empty string
   [nibNameText setStringValue:(const char *)""];
   [nibNameMatrix display];

   [object setPathInIB:[pathInIBText stringValue]];

   return [super ok: sender];
}

- setPathInIBText:sender { pathInIBText = sender; return self; }

- addNibName:(const char *)nibFileName
{
  BOOL isWhiteSpace = YES, alreadyGotIt;
  int  i, len;
  char tmpBuf[MAXPATHLEN + 1], *cellStr, *suffix;


  if (!nibFileName)
  {  return self;
  }
  i = 0; len = strlen(nibFileName);
  while ((i < len) && isWhiteSpace)
  {  if (!isspace(nibFileName[i++]))
     {  isWhiteSpace = NO;
     }
  }

  suffix = (char *)nibFileName + (strlen(nibFileName) - 4);
  if ((!isWhiteSpace) && !strcmp(".nib", suffix))
  {  // at this point, we know this is a nib file (or at least named one) and we want to add it to our list.
     // we don't, however, really want to add *this* file.  We want it to be in the project that this nib file is in.  
     // so, for the list, we really want to strip the pathname off the front and the .nib extension at the end.
     // we also want to message Project Builder to add this file to the project.
     // Actually, we also want to make sure that we don't already have this file in our list already.
     alreadyGotIt = NO;
     basename(nibFileName, ".nib", tmpBuf);
     for (i = 0; i < [[nibNameMatrix cellList] count]; i++)
     {  cellStr = (char *)[[[nibNameMatrix cellList] objectAt:i] stringValue];
        if (cellStr)
        {  if (!strcmp(cellStr, tmpBuf))
           {  alreadyGotIt = YES;
           }
        }
     }
     if (!alreadyGotIt)
     {  [nibNameMatrix addRow];
        [nibNameMatrix sizeToCells];
        [[nibNameMatrix cellAt:([nibNameMatrix cellCount] - 1) :0] setStringValue:tmpBuf];
        [nibNameMatrix scrollCellToVisible:([nibNameMatrix cellCount] - 1) :0];
     }
     else
     {  //NXLogError("<%s> already in the matrix.  I did NOT add it\n", tmpBuf);
     }
  }
  else
  {  //NXLogError("<%s> not a nib file.  I did NOT add it\n", nibFileName);
  }
  return self;
}



@end
